package services

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"longmen/server/config/global"
	"longmen/server/pkg/common/api_models"
	"longmen/server/pkg/common/helper/encrypt"
	"longmen/server/pkg/common/helper/timehelper"
	utils2 "longmen/server/pkg/common/helper/util"
	"longmen/server/pkg/common/report"
	"longmen/server/pkg/db/mysql/db_main"
	"longmen/server/pkg/db/mysql/models/models_main"
	"longmen/server/pkg/db/redis/cache"
	"net/http"
	"strings"
	"time"
)

func (s *Service) UpdateStatistics(column string, statistics *models_main.Statistics) error {
	fName := "UpdateStatistics"
	err := db_main.UpdateStatistics(statistics.Id, column, statistics)
	if err != nil {
		return fmt.Errorf("%s%s", utils2.Convert(fName), err.Error())
	}
	return nil
}

func (s *Service) InsertDownloadTimes(req *api_models.DownloadTimesReq) error {
	hash := strings.Replace(req.Hash, "\"", "", 2)
	uuid, err := global.GetRds().Get(hash).Result()
	if err != nil {
		return err
	}
	if uuid != req.DeviceId {
		return fmt.Errorf("验证失败")
	}
	var sem = 0
	if cache.IsSem(req.Source) {
		sem = 1
		cache.AddSemChannel(req.DeviceId)
	}
	if err := db_main.InsertDownloadTimes(req.DeviceId, req.Source, sem); err != nil {
		return err
	}
	return nil
}

func (s *Service) SetCache(uuid string) (string, error) {
	hash := encrypt.GenHashWithLength(11)
	err := global.GetRds().Set(hash, uuid, 30*time.Second).Err()
	if err != nil {
		return "", err
	}
	return hash, nil
}

type AttributeResp struct {
	Code             int    `json:"code"`
	Message          string `json:"message"`
	AdvIdfv          string `json:"adv_idfv"`
	AdvAndroidId     string `json:"adv_android_id"`
	IsDpOpen         bool   `json:"is_dp_open"`
	ActivationWindow int    `json:"activation_window"`
	ActiveTime       int64  `json:"active_time"`
	ActiveTouchTime  int64  `json:"active_touch_time"`
	LastTouchTime    int64  `json:"last_touch_time"`
	ProjectId        int64  `json:"project_id"`
	ProjectName      string `json:"project_name"`
	PromotionId      int64  `json:"promotion_id"`
	PromotionName    string `json:"promotion_name"`
	Aid              int    `json:"aid"`
	AidName          string `json:"aid_name"`
	Cid              int    `json:"cid"`
	CidName          string `json:"cid_name"`
	AdvertiserId     int64  `json:"advertiser_id"`
	ReqId            string `json:"req_id"`
	TrackId          string `json:"track_id"`
	CallbackParam    string `json:"callback_param"`
	CallbackUrl      string `json:"callback_url"`
	Mid1             int    `json:"mid1"`
	Mid2             int64  `json:"mid2"`
	Mid3             int    `json:"mid3"`
	Mid4             int    `json:"mid4"`
	Mid5             int    `json:"mid5"`
	Mid6             int    `json:"mid6"`
	ActiveTrackUrl   string `json:"active_track_url"`
	ActionTrackUrl   string `json:"action_track_url"`
	ConvertSource    string `json:"convert_source"`
	DemandId         int    `json:"demand_id"`
	ItemId           int    `json:"item_id"`
}

func (s *Service) SendAscribeReport(req *api_models.AscribeReportReq) error {
	record, err := report.NewAscribeReport().GetReportRecord(req.AndroidId)
	if err != nil {
		return fmt.Errorf("GetReportRecord 查询失败: %v", err)
	}
	var result = &AttributeResp{}
	var evenTyp = "next_day_open"
	if record != nil {
		// 如果表里有数据，则用当前时间减去激活的时间得到天数， 如果天数为1-7就调转化上报接口传入对应事件，
		// 如果天数 >= 30，则再次调实时归因接口，并更新last_touch_time callback_param，然后再调用转化接口传入active事件
		var aRes AttributeResp
		if record.Res != "" && json.Unmarshal([]byte(record.Res), &aRes) == nil {
			global.Log.Debugf("JSON 解码成功: %v", aRes)
			// 计算激活时间和当前时间之间的天数差
			loc, _ := time.LoadLocation(timehelper.DEFAULT_LOCATION_STR)
			now := time.Now().In(loc)
			activeTime := time.Unix(aRes.ActiveTime, 0).In(loc)

			nowDate := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, loc)
			activeDate := time.Date(activeTime.Year(), activeTime.Month(), activeTime.Day(), 0, 0, 0, 0, loc)

			daysDifference := int64(nowDate.Sub(activeDate).Hours() / 24)

			if daysDifference >= 1 && daysDifference <= 7 {
				// 处理1-7天的转化上报逻辑
				evenTypMp := map[int64]string{
					0: "active",
					1: "next_day_open",
					2: "retention_2d",
					3: "retention_3d",
					4: "retention_4d",
					5: "retention_5d",
					6: "retention_6d",
					7: "retention_7d",
				}
				var ok bool
				evenTyp, ok = evenTypMp[daysDifference]
				if ok {
					//如果天数为1-7就调转化上报接口传入对应事件
					trsReq := &api_models.AscribeTransformReq{
						EvenType: evenTyp,
						AscribeReportBaseReq: api_models.AscribeReportBaseReq{
							Platform:           req.Platform,
							IDFV:               req.IDFV,
							AndroidId:          req.AndroidId,
							CustomerActiveTime: req.CustomerActiveTime,
							Callback:           record.Callback,
							Res:                req.Res,
						},
					}
					err = s.SendAscribeTransform(trsReq)
					if err != nil {
						global.Log.Debugf("巨量转化失败:%v", err)
						return err
					}
				}
				return nil

			} else if daysDifference >= 30 {
				// 再次调用实时归因接口并更新last_touch_time和callback_param
				result, err = s.SendAscribeReportHttp(req)
				if err != nil {
					return err
				}
				aRes.CallbackParam = result.CallbackParam
				aRes.LastTouchTime = time.Now().UnixMilli()
				aresVal, _ := json.Marshal(aRes)
				err = report.NewAscribeReport().UpdateResById(record.ID, string(aresVal))
				if err != nil {
					global.Log.Debugf("更新last_touch_time和callback_param失败: %v", err)
					return err
				}
				//再调用转化接口传入active事件 👇
				evenTyp = "active"
			} else {
				// 中间天数跳过逻辑
				return nil
			}
		} else {
			global.Log.Debugf("JSON 解码失败: %v", err)
			return fmt.Errorf("JSON 解码失败: %v", err)
		}
	}

	if record == nil {
		//表里没有数据就掉抖音实时归因接口，获得last_touch_time   callback_param并存入表
		result, err = s.SendAscribeReportHttp(req)
		if err != nil {
			return err
		}
		//同时调用转化上报接口传入active事件 👇
		evenTyp = "active"
	}

	{
		//调用转化接口传入eventType事件 实现
		if result != nil && result.Code == 0 && result.CallbackParam != "" {
			req.Callback = result.CallbackParam
			var ascribeTransformReq api_models.AscribeTransformReq
			ascribeTransformReq.EvenType = evenTyp
			ascribeTransformReq.Platform = req.Platform
			ascribeTransformReq.AndroidId = req.AndroidId
			ascribeTransformReq.Callback = result.CallbackParam
			err := s.SendAscribeTransform(&ascribeTransformReq)
			if err != nil {
				global.Log.Debugf("巨量转化失败:%v", err)
			}
		}
		err = report.NewAscribeReport().InsertDB(req)
		if err != nil {
			return err
		}
	}
	return nil
}

func (s *Service) SendAscribeReportHttp(req *api_models.AscribeReportReq) (*AttributeResp, error) {
	req.CustomerActiveTime = time.Now().UnixMilli()

	global.Log.Infof("巨量归因 - 请求参数: %+v", req)

	url := "https://analytics.oceanengine.com/sdk/app/attribution"
	jsonValue, err1 := json.Marshal(req)
	if err1 != nil {
		return nil, fmt.Errorf("JSON 编码失败: %v", err1)
	}
	httpReq, err2 := http.NewRequest("POST", url, bytes.NewBuffer(jsonValue))
	if err2 != nil {
		return nil, fmt.Errorf("创建 HTTP 请求失败: %v", err2)
	}
	httpReq.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err3 := client.Do(httpReq)
	if err3 != nil {
		return nil, fmt.Errorf("发送请求失败: %v", err3)
	}
	defer func(Body io.ReadCloser) {
		err := Body.Close()
		if err != nil {

		}
	}(resp.Body)
	// 读取响应
	body, err4 := io.ReadAll(resp.Body)
	if err4 != nil {
		return nil, fmt.Errorf("读取响应失败: %v", err4)
	}
	global.Log.Infof("巨量归因 - 响应结果: %s", string(body))
	var result AttributeResp
	if err := json.Unmarshal(body, &result); err != nil {
		global.Log.Debugf("巨量归因: JSON解析失败: %v", err)
		return nil, fmt.Errorf("JSON解析失败: %v", err)
	}
	req.Res = string(body)
	return &result, nil
}

func (s *Service) SetAscribeTransform(req *api_models.AscribeTransformReq) error {
	record, err := report.NewAscribeReport().GetReportRecord(req.AndroidId)
	if err != nil {
		return err
	}
	if record == nil {
		return errors.New("该android_id未归因")
	}
	req.Callback = record.Callback
	err = s.SendAscribeTransform(req)
	if err != nil {
		global.Log.Debugf("巨量转化失败:%v", err)
		return err
	}
	return nil
}

func (s *Service) SendAscribeTransform(req *api_models.AscribeTransformReq) error {
	url := "https://analytics.oceanengine.com/api/v2/conversion"
	// 创建空的 map
	data := make(map[string]interface{})
	// 逐个赋值
	data["event_type"] = req.EvenType
	data["timestamp"] = time.Now().UnixMilli()

	// 创建嵌套的 map
	context := make(map[string]interface{})
	ad := make(map[string]interface{})
	device := make(map[string]interface{})

	// callback在归因返回的redis中取
	ad["callback"] = req.Callback
	device["platform"] = req.Platform
	device["android_id"] = req.AndroidId

	// 将嵌套的 map 赋值给 context
	context["ad"] = ad
	context["device"] = device
	// 将 context 赋值给 data
	data["context"] = context

	// 👇 新增：打印请求参数（原始 map 内容）
	global.Log.Infof("SendAscribeTransform - 请求参数: %+v", data)

	jsonValue, err1 := json.Marshal(data)
	if err1 != nil {
		return fmt.Errorf("JSON 编码失败: %v", err1)
	}
	httpReq, err2 := http.NewRequest("POST", url, bytes.NewBuffer(jsonValue))
	if err2 != nil {
		return fmt.Errorf("创建 HTTP 请求失败: %v", err2)
	}
	httpReq.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err3 := client.Do(httpReq)
	if err3 != nil {
		return fmt.Errorf("发送请求失败: %v", err3)
	}
	defer func(Body io.ReadCloser) {
		err := Body.Close()
		if err != nil {

		}
	}(resp.Body)
	// 读取响应
	body, err4 := io.ReadAll(resp.Body)
	if err4 != nil {
		return fmt.Errorf("读取响应失败: %v", err4)
	}
	global.Log.Infof("SendAscribeTransform 巨量转化 - 响应结果: %s", string(body))
	req.Res = string(body)
	err := report.NewAscribeTransform().InsertDB(req)
	if err != nil {
		global.Log.Debugf("巨量转化入库:%v", err)
		return err
	}
	return nil
}

func (s *Service) SendAscribeContact(data map[string]interface{}) error {
	jsonValue, err1 := json.Marshal(data)
	if err1 != nil {
		return fmt.Errorf("JSON 编码失败: %v", err1)
	}
	cacheKey := fmt.Sprintf(api_models.AscribeContactKey+"%d", time.Now().Unix())
	err := global.GetRds().Set(cacheKey, jsonValue, time.Hour*24).Err()
	if err != nil {
		return err
	}
	return nil
}

func (s *Service) CalRetentionDays(deviceId string) int64 {
	fName := "CalRetentionDays"

	downloadTimeUnix, err := db_main.GetDownloadTime(deviceId)
	if err != nil || downloadTimeUnix == 0 {
		global.Log.Errorf("%s error: %v", utils2.Convert(fName), err)
		return 0
	}

	loc, _ := time.LoadLocation(timehelper.DEFAULT_LOCATION_STR)
	now := time.Now().In(loc)
	downloadTime := time.Unix(downloadTimeUnix, 0).In(loc)

	nowDate := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, loc)
	downloadDate := time.Date(downloadTime.Year(), downloadTime.Month(), downloadTime.Day(), 0, 0, 0, 0, loc)

	days := int64(nowDate.Sub(downloadDate).Hours() / 24)
	if days < 0 {
		days = 0
	}
	return days
}
